﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;

namespace client.app
{
    public sealed class RSprite : comm.world.BObject
    {
        class Image : LayerImage
        {
            public List<comm.objst.RImage.Frame> FrameList = new List<comm.objst.RImage.Frame>();
            public uint FrameIndex = 0;

            RSprite _rSrpite = null;
            Texture2D _texture = null;
            SpriteBatch _spriteBatch = null;

            public Image(RSprite rSprite, Texture2D texture, string layerName)
                : base(layerName)
            {
                _rSrpite = rSprite;
                _texture = texture;
                _spriteBatch = new SpriteBatch(MainGame.Instance.GraphicsDevice);
            }

            protected override void OnUpdate(comm.TimeStat timeStat)
            {
                if (Display)
                {
                    var frame = FrameList[(int)FrameIndex];
                    DisplayX = _rSrpite.DisplayX - frame.CentreX;
                    DisplayY = _rSrpite.DisplayY - frame.CentreY;
                    Width = frame.Width;
                    Height = frame.Height;
                }
            }

            public override void Draw(comm.TimeStat timeStat)
            {
                if (Display)
                {
                    //System.Console.WriteLine(DisplayX + " " + DisplayY);

                    _spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied);
                    var frame = FrameList[(int)FrameIndex];
                    _spriteBatch.Draw(_texture,
                        new Rectangle((int)DisplayX, (int)DisplayY, frame.Width, frame.Height),
                        new Rectangle(frame.X, frame.Y, frame.Width, frame.Height), Color.White);
                    _spriteBatch.End();
                }

                base.Draw(timeStat);
            }
        }

        public string SpriteGroupName { get; private set; }
        public float DisplayX { get; set; }
        public float DisplayY { get; set; }

        comm.objst.RPack _rpack = null;
        comm.objst.RSprite _rsprite = null;
        comm.MainTimeline _mainTimeline = new comm.MainTimeline();
        Dictionary<string, Image> _imageDic = new Dictionary<string, Image>();
        LayerManager _layerManager = null;

        public RSprite(LayerManager layerManager)
        {
            _layerManager = layerManager;
        }

        public void LoadRSprite(string rpackFile, string spriteName)
        {
            System.Console.WriteLine(spriteName);
            _rpack = MainGame.RPackManager.LoadRPack(rpackFile);
            if (_rpack != null)
            {
                var sprites = _rpack.FindResource<comm.objst.RSprite>(spriteName);
                if (sprites.Length > 0)
                {
                    _rsprite = sprites[0];
                    ChangeGroup(comm.objst.RSprite.DEFAULT_GROUP_KEY);
                }
            }
        }
        public void ChangeGroup(string spriteGroupName)
        {
            var newImageDic = new Dictionary<string, Image>();
            if (_rsprite != null)
            {
                var groups = _rsprite.FindGroup(spriteGroupName);
                if (groups.Length > 0)
                {
                    SpriteGroupName = spriteGroupName;
                    _mainTimeline.End();
                    _mainTimeline.ClearAllLine();

                    var group = groups[0];
                    foreach (var elKey in group.ElementDic.Keys)
                    {
                        _rsprite.FindGroup(spriteGroupName);
                        var item = group.ElementDic[elKey];
                        var imgKey = comm.GUID.NewString();
                        if (item is comm.objst.RSprite.Timeline)
                        {
                            var tl = (comm.objst.RSprite.Timeline)item;
                            var line = new comm.Timeline(tl.GetResTimes(_rpack), (uint)tl.StartType, tl.BeginTime, tl.EndTime, tl.MaxLoopCount);
                            line.Tag = imgKey;
                            line.OnEnterTimeCallback = EnterTimeCallback;
                            line.OnCompleteCallback = CompleteCallback;

                            if (tl is comm.objst.RSprite.Image)
                            {
                                #region Image
                                var image = (comm.objst.RSprite.Image)tl;
                                var rimage = _rpack.GetResource<comm.objst.RImage>(tl.ResKey);
                                if (rimage != null)
                                {
                                    var frame = rimage.GetFrame(image.FrameIndex);
                                    if (frame != null)
                                    {
                                        var texId = Encoding.UTF8.GetString(rimage.ImageBytes);
                                        var img = new Image(this, MainGame.RPackManager.GetTexture(texId), image.MapLayerType.ToString());
                                        img.FrameList.Add(frame);
                                        newImageDic.Add(imgKey, img);

                                        _mainTimeline.AddLine(elKey, line);
                                    }
                                }
                                #endregion
                            }
                            else if (tl is comm.objst.RSprite.KeyFrameAnim)
                            {
                                #region kfanim
                                var kf = (comm.objst.RSprite.KeyFrameAnim)tl;
                                var rkf = _rpack.GetResource<comm.objst.RKeyFrameAnim>(tl.ResKey);
                                if (rkf != null && rkf.ImageDic.ContainsKey(kf.ImageKey))
                                {
                                    var img = rkf.ImageDic[kf.ImageKey];
                                    var rimage = _rpack.GetResource<comm.objst.RImage>(img.ResKey);
                                    if (rimage != null)
                                    {
                                        var texId = Encoding.UTF8.GetString(rimage.ImageBytes);
                                        var img2 = new Image(this, MainGame.RPackManager.GetTexture(texId), kf.MapLayerType.ToString());
                                        foreach (var frameIndex in img.FrameList)
                                        {
                                            var frame = rimage.GetFrame(frameIndex);
                                            img2.FrameList.Add(frame);
                                        }
                                        newImageDic.Add(imgKey, img2);

                                        _mainTimeline.AddLine(elKey, line);
                                    }
                                }
                                #endregion
                            }
                        }
                    }

                    _mainTimeline.Begin();
                }
            }
            var kvs = _imageDic.ToArray();
            foreach (var kv in kvs)
            {
                kv.Value.Remove();
            }
            _imageDic.Clear();
            foreach (var key in newImageDic.Keys)
            {
                var image = newImageDic[key];
                _layerManager.AddImage(image);
                _imageDic.Add(key, image);
            }
        }

        Image GetImage(string key)
        {
            Image obj;
            _imageDic.TryGetValue(key, out obj);
            return obj;
        }

        void EnterTimeCallback(comm.Timeline line)
        {
            var image = GetImage(line.Tag.ToString());
            if (image != null)
            {
                image.Display = true;
                image.FrameIndex = line.TimeIndex;
            }
        }
        void CompleteCallback(comm.Timeline line)
        {
            var image = GetImage(line.Tag.ToString());
            if (image != null)
            {
                image.Display = false;
            }
        }

        protected override void OnUpdate(comm.TimeStat timeStat)
        {
            _mainTimeline.Update();
        }
    }
}
